package xin.yangshuai.juc01.hello;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Hello
 *
 * @author shuai
 * @date 2022/2/10
 */

class Share {
    private int number = 0;

    public synchronized void incr(int i) throws InterruptedException {

        System.out.println(Thread.currentThread().getName() + i + "::incr 拿到锁");
        while (number != 0) {
            System.out.println(Thread.currentThread().getName() + i + "::incr 等待，释放锁");
            this.wait();
            System.out.println(Thread.currentThread().getName() + i + "::incr 等待后重新拿到锁");
        }
        number++;
        System.out.println(Thread.currentThread().getName() + i + "::incr 加一操作 " + number);
        this.notifyAll();
        System.out.println(Thread.currentThread().getName() + i + "::incr 唤醒所有");

//        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName() + i + "::incr 释放锁");
    }

    public synchronized void decr(int i) throws InterruptedException {

        System.out.println(Thread.currentThread().getName() + i + "::decr 拿到锁");
        while (number != 1) {
            System.out.println(Thread.currentThread().getName() + i + "::decr 等待，释放锁");
            this.wait();
            System.out.println(Thread.currentThread().getName() + i + "::decr 等待后重新拿到锁");
        }
        number--;
        System.out.println(Thread.currentThread().getName() + i + "::decr 减一操作 " + number);
        this.notifyAll();
        System.out.println(Thread.currentThread().getName() + i + "::decr 唤醒所有");

//        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName() + i + "::decr 释放锁");
    }
}

class Share1 {
    private int number = 0;

    private Lock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    public void incr(int i) throws InterruptedException {

        lock.lock();

        try {
            System.out.println(Thread.currentThread().getName() + i + ":lock:incr 拿到锁");
            while (number != 0) {
                System.out.println(Thread.currentThread().getName() + i + ":lock:incr 等待，释放锁");
                condition.await();
                System.out.println(Thread.currentThread().getName() + i + ":lock:incr 等待后重新拿到锁");
            }
            number++;
            System.out.println(Thread.currentThread().getName() + i + ":lock:incr 加一操作 " + number);
            condition.signalAll();
            System.out.println(Thread.currentThread().getName() + i + ":lock:incr 唤醒所有");
            System.out.println(Thread.currentThread().getName() + i + ":lock:incr 释放锁");

        } finally {
            lock.unlock();
        }
    }

    public void decr(int i) throws InterruptedException {

        lock.lock();

        try {
            System.out.println(Thread.currentThread().getName() + i + ":lock:decr 拿到锁");
            while (number != 1) {
                System.out.println(Thread.currentThread().getName() + i + ":lock:decr 等待，释放锁");
                condition.await();
                System.out.println(Thread.currentThread().getName() + i + ":lock:decr 等待后重新拿到锁");
            }
            number--;
            System.out.println(Thread.currentThread().getName() + i + ":lock:decr 减一操作 " + number);
            condition.signal();
            System.out.println(Thread.currentThread().getName() + i + ":lock:decr 唤醒所有");
            System.out.println(Thread.currentThread().getName() + i + ":lock:decr 释放锁");
        } finally {
            lock.unlock();
        }


    }
}


public class Hello {

    public static void main(String[] args) {
        Share1 share = new Share1();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        share.incr(i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "AA").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        share.decr(i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "BB").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        share.incr(i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "CC").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        share.decr(i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "DD").start();
    }
}
